import fs from 'fs-extra'
import {fileURLToPath} from 'node:url'
import path from 'node:path'
import recursiveReaddirFiles from 'recursive-readdir-files'
import type {IFileDirStat} from 'recursive-readdir-files'
import {create} from './create.js'
import {ParsedArgs} from 'minimist'

export const __filename = fileURLToPath(import.meta.url)
/**
 * 搜索数据路径
 * */
export const SEARCH_DATA_CACHE = path.resolve(process.cwd(), 'node_modules/.cache/refs-cli/data.json')
/**
 * 把附件 copy 到打包目录
 */
export async function copyAttachment(options: Options) {
    await fs.copy(options.config.attachmentPath, path.resolve(options.config.outputPath, options.config.attachmentDir))
}
/**
 * 把源码中的 style 复制到打包结果目录中的 style
 */
export async function copyCSSFile(options: Options) {
    await fs.copy(path.resolve(options.static_path, './style'), path.resolve(options.config.outputPath, 'style'))
}
/**
 * 把源码中的 js 复制到打包结果目录中的 js
 */
export async function copyJSFile(options: Options) {
    await fs.copy(path.resolve(options.static_path, './js'), path.resolve(options.config.outputPath, 'js'))
}

export interface Config {
    title?: string
    description?: string
    keywords?: string
    footer?: string
    license?: string
    giscus?: Record<string, string>
    'data-info'?: string
    search?: {
        label: string
        placeholder: string
        cancel: string
    }
    editor?: {
        label: string
        disabled?: boolean
    }
    github?: {
        url: string
    }
    home?: {
        label: string
        url: string
    }
    inputDir?: string
    inputPath?: string
    outputDir?: string
    outputPath?: string
    attachmentDir?: string
    attachmentPath?: string
    server?: {
        port: number
        root: string
        file: string
    }
}

export interface Options extends Partial<ParsedArgs> {
    static_path?: string
    watch?: boolean
    build?: boolean
    force?: boolean
    config?: Config
}

export async function run(options: Options) {
    try {
        // 情况输出目录
        await fs.ensureDir(options.config.outputPath)
        await fs.emptyDir(options.config.outputPath)
        // 搬运附件
        await copyAttachment(options)
        // 搬运assets
        await copyCSSFile(options)
        await copyJSFile(options)
        // 写到node_module/.cache里
        await fs.ensureFile(SEARCH_DATA_CACHE)
        await fs.writeFile(SEARCH_DATA_CACHE, '{}')
        // 写到输出目录里
        await fs.writeFile(path.resolve(options.config.outputPath, 'data.json'), '[]')
        await fs.writeFile(path.resolve(options.config.outputPath, 'data.js'), `const REFS_DATA = []`)
        // 列出目标项目下的所有md文件
        const files = await recursiveReaddirFiles(process.cwd(), {
            ignored: /[\\/](node_modules|\.git)/g,
            exclude: /(\.json|\.mjs|CONTRIBUTING\.md)$/,
            filter: (item) => item.ext === 'md',
        })
        // md转html
        createHTML(files, options)
    } catch (error) {
        console.log('ERR:', error)
    }
}
/**
 * 递归函数，根据 files[num] 创建html
 * @param files
 * @param opts
 * @param num number 自增索引
 * @returns
 */
export async function createHTML(files: IFileDirStat[] = [], opts: Options, num = 0) {
    const dataFile = files[num]
    if (!dataFile) {
        console.log(' \n done!\n')
        return
    }
    ++num
    const githubURL =
        opts.config.github?.url && opts.config.editor?.disabled !== true
            ? `${opts.config.github.url || opts.config.github}/blob/main/${path
                  .relative(process.cwd(), dataFile.path)
                  .replace(path.sep, '/')}`
            : ''

    const mdstr = await fs.readFile(dataFile.path)
    const htmlPath = path.relative(opts.config.inputPath, dataFile.path)

    const outputHTMLPath = path
        .resolve(opts.config.outputPath, opts.config.inputDir, htmlPath)
        .replace(/README.md$/i, 'index.html')
        .replace(/.md$/, '.html')

    await fs.ensureDir(path.dirname(outputHTMLPath))

    const options = {
        filename: path.basename(outputHTMLPath, '.html'),
        isHome: /README.md$/.test(path.relative(process.cwd(), dataFile.path)),
        githubURL,
        homePath: path.relative(path.dirname(outputHTMLPath), path.resolve(opts.config.outputPath, 'index.html')),
        css: [
            path.relative(path.dirname(outputHTMLPath), path.resolve(opts.config.outputPath, 'style/style.css')),
            path.relative(path.dirname(outputHTMLPath), path.resolve(opts.config.outputPath, 'style/katex.css')),
        ],
    }
    // console.log(
    //     '\n\n\nopts:\n',opts,
    //     '\nhtmlPath:\n',htmlPath,
    //     '\noutputHTMLPath:\n', outputHTMLPath,
    //     '\noptions:\n', options
    // )
    const {html, data} = create(mdstr.toString(), {...options, ...opts})
    if (!options.isHome) {
        const searchData = await fs.readJSON(SEARCH_DATA_CACHE)
        // 搜索栏的导航菜单，各项对应的路径
        data.path = `/${path.relative(opts.config.outputPath, outputHTMLPath).replace(/[\\/]/g, '/')}`

        searchData[options.filename] = data
        searchData.name = options.filename
        searchData[options.filename].name = options.filename
        await fs.writeJSON(SEARCH_DATA_CACHE, searchData)
        const resultSearchData = Object.keys({...searchData})
            .map((name) => searchData[name])
            .filter((item) => typeof item !== 'string')
        await fs.writeJSON(path.resolve(opts.config.outputPath, 'data.json'), resultSearchData)
        const SEARCH_DATA_JS = path.resolve(opts.config.outputPath, 'data.js')
        await fs.writeFile(SEARCH_DATA_JS, `const REFS_DATA = ${JSON.stringify(resultSearchData)}`)
    }
    await fs.writeFile(outputHTMLPath, html as string)
    console.log(`♻️ \x1b[32;1m ${path.relative(opts.config.outputPath, outputHTMLPath)} \x1b[0m`)
    createHTML(files, opts, num)
}

export const pkg = fs.readJSONSync(path.join(__filename, '../../../package.json'))

export const helpStr = `
  Usage: \x1b[34;1mquickref-cli\x1b[0m [output-dir] [--help|h]
    Displays help information.

  Options:
    --version, -v   Show version number
    --help, -h      Displays help information.
    --watch, -w     Watch and compile Markdown files.

  Example:
    $\x1b[35m npx\x1b[0m quickref-cli
    $\x1b[35m quickref-cli\x1b[0m --watch

    quickref-cli@v${pkg.version}
`
